/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/


#include <string.h>
#include "flgrCoreData.h"
#include "flgrCoreDispatch.h"
#include "flgrCoreIO.h"
#include "flgrCoreRoI.h"

/*!
 * \ingroup group_fulguro_core_copy
 * @{
 */

#define FLGR_MACRO_EXTRACT_REGION_1D(dtype)	\
  int spp = datroi->spp;			\
  int length = datroi->length*spp;		\
  dtype *proi,*psrc;				\
						\
  FLGR_DECLARE_FUNCTION;			\
						\
  psrc = (dtype*) datsrc->array+x*spp;		\
  proi = (dtype*) datroi->array;		\
  						\
  memcpy(proi,psrc,length*sizeof(dtype))

void flgr1d_extract_region_fgBIT(FLGR_Data1D *datroi, FLGR_Data1D *datsrc, int x) {
  int j,k;
  int length = (datroi->length+x)*datroi->spp;
  fgBIT *proi,*psrc,val;

  FLGR_DECLARE_FUNCTION;

  psrc = (fgBIT*) datsrc->array;
  proi = (fgBIT*) datroi->array;

  for(j=x,k=0 ; j<length ; j++,k++) {
    val = flgr_get_array_fgBIT(psrc,j);
    flgr_set_array_fgBIT(proi,k,val);
  }

}
void flgr1d_extract_region_fgUINT8(FLGR_Data1D *datroi, FLGR_Data1D *datsrc, int x) {
  FLGR_MACRO_EXTRACT_REGION_1D(fgUINT8);
}
void flgr1d_extract_region_fgUINT16(FLGR_Data1D *datroi, FLGR_Data1D *datsrc, int x) {
  FLGR_MACRO_EXTRACT_REGION_1D(fgUINT16);
}
void flgr1d_extract_region_fgUINT32(FLGR_Data1D *datroi, FLGR_Data1D *datsrc, int x) {
  FLGR_MACRO_EXTRACT_REGION_1D(fgUINT32);
}
void flgr1d_extract_region_fgINT8(FLGR_Data1D *datroi, FLGR_Data1D *datsrc, int x) {
  FLGR_MACRO_EXTRACT_REGION_1D(fgINT8);
}
void flgr1d_extract_region_fgINT16(FLGR_Data1D *datroi, FLGR_Data1D *datsrc, int x) {
  FLGR_MACRO_EXTRACT_REGION_1D(fgINT16);
}
void flgr1d_extract_region_fgINT32(FLGR_Data1D *datroi, FLGR_Data1D *datsrc, int x) {
  FLGR_MACRO_EXTRACT_REGION_1D(fgINT32);
}
void flgr1d_extract_region_fgFLOAT32(FLGR_Data1D *datroi, FLGR_Data1D *datsrc, int x) {
  FLGR_MACRO_EXTRACT_REGION_1D(fgFLOAT32);
}
void flgr1d_extract_region_fgFLOAT64(FLGR_Data1D *datroi, FLGR_Data1D *datsrc, int x) {
  FLGR_MACRO_EXTRACT_REGION_1D(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Extract a region of interest (ROI)
 *  @param datsrc : a pointer to a FLGR_Data1D
 *  @param datroi  : a pointer to a FLGR_Data1D smaller than datsrc
 *  @param x       : x offset in destinnation
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_extract_region(FLGR_Data1D *datroi, FLGR_Data1D *datsrc, int x) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datroi==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }
  
  if( (ret=flgr1d_is_data_same_type(datsrc,datroi)) != FLGR_RET_OK ) {
    POST_ERROR("ROI and destination have different or illegal types");
    return ret;
  }

  if( (ret=flgr1d_is_data_same_spp(datsrc,datroi)) != FLGR_RET_OK ) {
    POST_ERROR("ROI and destination have different sample per pixels");
    return ret;
  }

  if( (x+datroi->length) > datsrc->length ) {
    POST_ERROR("The region of interest is too large");
    return FLGR_RET_SIZE_ERROR;
  }

  FLGR_DISPATCH_PROCEDURE(datsrc->type,flgr1d_extract_region,datroi,datsrc,x);
}





#define FLGR_MACRO_EXTRACT_REGION_2D(dtype)				\
  FLGR_Data1D **psrc = datsrc->row+y;					\
  FLGR_Data1D **proi = datroi->row;					\
  int i;								\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(i=0 ; i<datroi->size_y ; i++,psrc++,proi++) {			\
    flgr1d_extract_region_##dtype(*proi,*psrc, x);			\
  }									\
  return

void flgr2d_extract_region_fgBIT(FLGR_Data2D *datroi, FLGR_Data2D *datsrc, int x, int y) {
  FLGR_MACRO_EXTRACT_REGION_2D(fgBIT);
}
void flgr2d_extract_region_fgUINT8(FLGR_Data2D *datroi, FLGR_Data2D *datsrc, int x, int y) {
  FLGR_MACRO_EXTRACT_REGION_2D(fgUINT8);
}
void flgr2d_extract_region_fgUINT16(FLGR_Data2D *datroi, FLGR_Data2D *datsrc, int x, int y) {
  FLGR_MACRO_EXTRACT_REGION_2D(fgUINT16);
}
void flgr2d_extract_region_fgUINT32(FLGR_Data2D *datroi, FLGR_Data2D *datsrc, int x, int y) {
  FLGR_MACRO_EXTRACT_REGION_2D(fgUINT32);
}
void flgr2d_extract_region_fgINT8(FLGR_Data2D *datroi, FLGR_Data2D *datsrc, int x, int y) {
  FLGR_MACRO_EXTRACT_REGION_2D(fgINT8);
}
void flgr2d_extract_region_fgINT16(FLGR_Data2D *datroi, FLGR_Data2D *datsrc, int x, int y) {
  FLGR_MACRO_EXTRACT_REGION_2D(fgINT16);
}
void flgr2d_extract_region_fgINT32(FLGR_Data2D *datroi, FLGR_Data2D *datsrc, int x, int y) {
  FLGR_MACRO_EXTRACT_REGION_2D(fgINT32);
}
void flgr2d_extract_region_fgFLOAT32(FLGR_Data2D *datroi, FLGR_Data2D *datsrc, int x, int y) {
  FLGR_MACRO_EXTRACT_REGION_2D(fgFLOAT32);
}
void flgr2d_extract_region_fgFLOAT64(FLGR_Data2D *datroi, FLGR_Data2D *datsrc, int x, int y) {
  FLGR_MACRO_EXTRACT_REGION_2D(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Extract a region of interest (ROI)
 *  @param datsrc  : a pointer to a FLGR_Data2D
 *  @param datroi  : a pointer to a FLGR_Data2D smaller than datsrc
 *  @param x       : column offset in destinnation
 *  @param y       : row offset in destinnation
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_extract_region(FLGR_Data2D *datroi, FLGR_Data2D *datsrc, int x, int y) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datroi==NULL) || (datsrc==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }
  
  if( (ret=flgr2d_is_data_same_type(datsrc,datroi)) != FLGR_RET_OK ) {
    POST_ERROR("ROI and destination have different or illegal types");
    return ret;
  }

  if( (ret=flgr2d_is_data_same_spp(datsrc,datroi)) != FLGR_RET_OK ) {
    POST_ERROR("ROI and destination have different sample per pixels");
    return ret;
  }

  if( (x+datroi->size_x) > datsrc->size_x ) {
    POST_ERROR("The region of interest is too large");
    return FLGR_RET_SIZE_ERROR;
  }

  if( (y+datroi->size_y) > datsrc->size_y ) {
    POST_ERROR("The region of interest is too large");
    return FLGR_RET_SIZE_ERROR;
  }

  FLGR_DISPATCH_PROCEDURE(datsrc->type,flgr2d_extract_region,datroi,datsrc,x,y);
}














#define FLGR_MACRO_INSERT_REGION_1D(dtype)	\
  int spp = datroi->spp;			\
  int length = datroi->length*spp;		\
  dtype *proi,*pdest;				\
						\
  FLGR_DECLARE_FUNCTION;			\
						\
  pdest  = (dtype*) datdest->array+x*spp;	\
  proi = (dtype*) datroi->array;		\
  						\
  memcpy(pdest,proi,length*sizeof(dtype))

void flgr1d_insert_region_fgBIT(FLGR_Data1D *datdest, FLGR_Data1D *datroi, int x) {
  int j,k;
  int length = (datroi->length+x)*datroi->spp;
  fgBIT *proi,*pdest,val;

  FLGR_DECLARE_FUNCTION;

  pdest  = (fgBIT*) datdest->array;
  proi = (fgBIT*) datroi->array;

  for(j=x,k=0 ; j<length ; j++,k++) {
    val = flgr_get_array_fgBIT(proi,k);
    flgr_set_array_fgBIT(pdest,j,val);
  }

}
void flgr1d_insert_region_fgUINT8(FLGR_Data1D *datdest, FLGR_Data1D *datroi, int x) {
  FLGR_MACRO_INSERT_REGION_1D(fgUINT8);
}
void flgr1d_insert_region_fgUINT16(FLGR_Data1D *datdest, FLGR_Data1D *datroi, int x) {
  FLGR_MACRO_INSERT_REGION_1D(fgUINT16);
}
void flgr1d_insert_region_fgUINT32(FLGR_Data1D *datdest, FLGR_Data1D *datroi, int x) {
  FLGR_MACRO_INSERT_REGION_1D(fgUINT32);
}
void flgr1d_insert_region_fgINT8(FLGR_Data1D *datdest, FLGR_Data1D *datroi, int x) {
  FLGR_MACRO_INSERT_REGION_1D(fgINT8);
}
void flgr1d_insert_region_fgINT16(FLGR_Data1D *datdest, FLGR_Data1D *datroi, int x) {
  FLGR_MACRO_INSERT_REGION_1D(fgINT16);
}
void flgr1d_insert_region_fgINT32(FLGR_Data1D *datdest, FLGR_Data1D *datroi, int x) {
  FLGR_MACRO_INSERT_REGION_1D(fgINT32);
}
void flgr1d_insert_region_fgFLOAT32(FLGR_Data1D *datdest, FLGR_Data1D *datroi, int x) {
  FLGR_MACRO_INSERT_REGION_1D(fgFLOAT32);
}
void flgr1d_insert_region_fgFLOAT64(FLGR_Data1D *datdest, FLGR_Data1D *datroi, int x) {
  FLGR_MACRO_INSERT_REGION_1D(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Insert a region of interest (ROI)
 *  @param datdest : a pointer to a FLGR_Data1D
 *  @param datroi  : a pointer to a FLGR_Data1D smaller than datdest
 *  @param x       : x offset in destinnation
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr1d_insert_region(FLGR_Data1D *datdest, FLGR_Data1D *datroi, int x) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datroi==NULL) || (datdest==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }
  
  if( (ret=flgr1d_is_data_same_type(datroi,datroi)) != FLGR_RET_OK ) {
    POST_ERROR("ROI and destination have different or illegal types");
    return ret;
  }

  if( (ret=flgr1d_is_data_same_spp(datroi,datroi)) != FLGR_RET_OK ) {
    POST_ERROR("ROI and destination have different sample per pixels");
    return ret;
  }

  if( (x+datroi->length) > datdest->length ) {
    POST_ERROR("The region of interest is too large");
    return FLGR_RET_SIZE_ERROR;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr1d_insert_region,datdest,datroi,x);
}






#define FLGR_MACRO_INSERT_REGION_2D(dtype)				\
  FLGR_Data1D **pdest = datdest->row+y;					\
  FLGR_Data1D **proi = datroi->row;					\
  int i;								\
									\
  FLGR_DECLARE_FUNCTION;						\
									\
  for(i=0 ; i<datroi->size_y ; i++,pdest++,proi++) {			\
    flgr1d_insert_region_##dtype(*pdest,*proi, x);			\
  }									\
  return

void flgr2d_insert_region_fgBIT(FLGR_Data2D *datdest, FLGR_Data2D *datroi, int x, int y) {
  FLGR_MACRO_INSERT_REGION_2D(fgBIT);
}
void flgr2d_insert_region_fgUINT8(FLGR_Data2D *datdest, FLGR_Data2D *datroi, int x, int y) {
  FLGR_MACRO_INSERT_REGION_2D(fgUINT8);
}
void flgr2d_insert_region_fgUINT16(FLGR_Data2D *datdest, FLGR_Data2D *datroi, int x, int y) {
  FLGR_MACRO_INSERT_REGION_2D(fgUINT16);
}
void flgr2d_insert_region_fgUINT32(FLGR_Data2D *datdest, FLGR_Data2D *datroi, int x, int y) {
  FLGR_MACRO_INSERT_REGION_2D(fgUINT32);
}
void flgr2d_insert_region_fgINT8(FLGR_Data2D *datdest, FLGR_Data2D *datroi, int x, int y) {
  FLGR_MACRO_INSERT_REGION_2D(fgINT8);
}
void flgr2d_insert_region_fgINT16(FLGR_Data2D *datdest, FLGR_Data2D *datroi, int x, int y) {
  FLGR_MACRO_INSERT_REGION_2D(fgINT16);
}
void flgr2d_insert_region_fgINT32(FLGR_Data2D *datdest, FLGR_Data2D *datroi, int x, int y) {
  FLGR_MACRO_INSERT_REGION_2D(fgINT32);
}
void flgr2d_insert_region_fgFLOAT32(FLGR_Data2D *datdest, FLGR_Data2D *datroi, int x, int y) {
  FLGR_MACRO_INSERT_REGION_2D(fgFLOAT32);
}
void flgr2d_insert_region_fgFLOAT64(FLGR_Data2D *datdest, FLGR_Data2D *datroi, int x, int y) {
  FLGR_MACRO_INSERT_REGION_2D(fgFLOAT64);
}
//////////////////////////////////////////////////////////////////
/*! Insert a region of interest (ROI)
 *  @param datdest : a pointer to a FLGR_Data2D
 *  @param datroi  : a pointer to a FLGR_Data2D smaller than datdest
 *  @param x       : column offset in destinnation
 *  @param y       : row offset in destinnation
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr2d_insert_region(FLGR_Data2D *datdest, FLGR_Data2D *datroi, int x, int y) {
  FLGR_Ret ret;

  FLGR_DECLARE_FUNCTION;

  if((datroi==NULL) || (datdest==NULL)) {
    POST_ERROR("Null objects!\n");
    return FLGR_RET_NULL_OBJECT;
  }
  
  if( (ret=flgr2d_is_data_same_type(datroi,datroi)) != FLGR_RET_OK ) {
    POST_ERROR("ROI and destination have different or illegal types");
    return ret;
  }

  if( (ret=flgr2d_is_data_same_spp(datroi,datroi)) != FLGR_RET_OK ) {
    POST_ERROR("ROI and destination have different sample per pixels");
    return ret;
  }

  if( (x+datroi->size_x) > datdest->size_x ) {
    POST_ERROR("The region of interest is too large");
    return FLGR_RET_SIZE_ERROR;
  }

  if( (y+datroi->size_y) > datdest->size_y ) {
    POST_ERROR("The region of interest is too large");
    return FLGR_RET_SIZE_ERROR;
  }

  FLGR_DISPATCH_PROCEDURE(datdest->type,flgr2d_insert_region,datdest,datroi,x,y);
}


//!@}
